using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace PenguinLevelEditor
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";


            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 760;

            m_tileTextureList = new List<Texture2D>();
            m_mouseInput = new MouseInput();
            this.IsMouseVisible = true;
            Components.Add(new GamerServicesComponent(this));
            
            
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            m_nullTexture = Content.Load<Texture2D>(@"blank");
            // Load tile textures
                
            m_tileTextureList.Add(Content.Load<Texture2D>(@"Tiles/ice"));
            m_tileTextureList.Add(Content.Load<Texture2D>(@"Tiles/rock"));
            m_tileTextureList.Add(Content.Load<Texture2D>(@"Tiles/sand"));
            m_tileTextureList.Add(Content.Load<Texture2D>(@"Tiles/slipperyice"));
            m_tileTextureList.Add(Content.Load<Texture2D>(@"Tiles/hole"));
            m_tileTextureList.Add(Content.Load<Texture2D>(@"Tiles/thinice"));

            m_bearStartTexture = Content.Load<Texture2D>(@"bear");

            m_startFlagTexture = Content.Load<Texture2D>(@"startflag");
            m_endFlagTexture = Content.Load<Texture2D>(@"finishflag");

            m_grid = new Grid(m_nullTexture, m_tileTextureList);

            m_grid.m_startFlagTexture = m_startFlagTexture;
            m_grid.m_finishFlagTexture = m_endFlagTexture;
            m_grid.m_bearStartTexture = m_bearStartTexture;

            m_font = Content.Load<SpriteFont>(@"Arial"); 
            m_text = new Text(spriteBatch, m_font);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            m_mouseInput.Update(gameTime);
            m_currentKeyState = Keyboard.GetState();

           

            if (m_mouseInput.m_middleButtonPressed)
            {
                // scroll
                m_scroll.X -= (m_mouseInput.m_currentState.X - m_mouseInput.m_previousState.X) * 2;
                m_scroll.Y -= (m_mouseInput.m_currentState.Y - m_mouseInput.m_previousState.Y) * 2;

            }
            if (m_mouseInput.m_leftButtonPressed && !Guide.IsVisible)
            {
                // place
                int gridX = (m_mouseInput.m_currentState.X + (int)(m_scroll.X / 2)) / 32;
                int gridY = (m_mouseInput.m_currentState.Y + (int)(m_scroll.Y/ 2)) / 32;

           if (m_text.TestDrawClickText(10, 10, m_path, m_mouseInput.m_currentState.X, m_mouseInput.m_currentState.Y, m_mouseInput.m_leftButtonPressed))
            {
 
           } else {

                if (OnGrid(gridX,gridY))
                {
                    m_grid.m_grid[gridX, gridY].m_tileType = m_currentTileType;
                    
                }
           }
            }
            if (m_mouseInput.m_rightButtonPressed)
            {
                // cycle tiles
                if ((int)m_currentTileType == Enum.GetValues(typeof(Tile.TileTypes)).Length - 1)
                {
                    m_currentTileType = 0;
                }
                else
                {
                    m_currentTileType++;
                }
            }
            if (m_currentKeyState.IsKeyDown(Keys.F1) && m_previousKeyState.IsKeyUp(Keys.F1))
            {
                int gridX = (m_mouseInput.m_currentState.X + (int)(m_scroll.X / 2)) / 32;
                int gridY = (m_mouseInput.m_currentState.Y + (int)(m_scroll.Y / 2)) / 32;
                m_grid.PlaceStartFlag(gridX, gridY);
            }
            if (m_currentKeyState.IsKeyDown(Keys.F2) && m_previousKeyState.IsKeyUp(Keys.F2))
            {
                int gridX = (m_mouseInput.m_currentState.X + (int)(m_scroll.X / 2)) / 32;
                int gridY = (m_mouseInput.m_currentState.Y + (int)(m_scroll.Y / 2)) / 32;

                m_grid.PlaceFinishFlag(gridX, gridY);
            }
            if (m_currentKeyState.IsKeyDown(Keys.F3) && m_previousKeyState.IsKeyUp(Keys.F3))
            {
                int gridX = (m_mouseInput.m_currentState.X + (int)(m_scroll.X / 2)) / 32;
                int gridY = (m_mouseInput.m_currentState.Y + (int)(m_scroll.Y / 2)) / 32;

                m_grid.PlaceBear(gridX, gridY);
            }
            if (m_currentKeyState.IsKeyDown(Keys.F4) && m_previousKeyState.IsKeyUp(Keys.F4))
            {
                m_grid.ClearBears();
            }
            if (m_currentKeyState.IsKeyDown(Keys.F5) && m_previousKeyState.IsKeyUp(Keys.F5))
            {
                m_grid.Load(m_path);
            }
            if (m_currentKeyState.IsKeyDown(Keys.F6) && m_previousKeyState.IsKeyUp(Keys.F6))
            {
                m_grid.Save(m_path);
            }

            m_mouseInput.CompleteUpdate();
            m_previousKeyState = m_currentKeyState;

            base.Update(gameTime);
        }

        private bool OnGrid(int x, int y)
        {
            if (x >= 0 && x < m_grid.Width && y >= 0 && y < m_grid.Height)
            {
                return true; 
            }
            return false;
        }

        /*private void UpdateKeys()
        {
            KeyboardState keyState = Keyboard.GetState();

            Keys[] currentKeys = keyState.GetPressedKeys();
            Keys[] lastKeys = oldKeyState.GetPressedKeys();

            bool found = false;

            for (int i = 0; i < currentKeys.Length; i++) {

                found = false;
                for (int y=0;y<lastKeys.Length;y++) {
                    if (currentKeys[i] == lastKeys[y]) {
                        found = true;
                    }
                    break;
                }
                if (!found) {
                    PressKey(currentKeys[i]);
                }

            }
            oldKeyState = keyState;
        }

        private void PressKey(Keys key)
        {
            string t = String.Empty;
            switch (editMode)
            {
                case EditingMode.Path:
                    t = m_path;
                    break;
                default:
                    return;

            }

            if (key == Keys.Back)
            {
                if (t.Length > 0)
                {
                    t = t.Substring(0, t.Length - 1);
                }
            }
            else if (key == Keys.Enter)
            {
                editMode = EditingMode.None;
            }
            else
            {
                t = (t + (char)key).ToLower();
            }

            switch (editMode)
            {
                case EditingMode.Path:
                    m_path = t;
                    break;
            }

        }*/

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            m_grid.Draw(gameTime, spriteBatch,m_scroll);

            if (m_text.DrawClickText(10, 10, m_path, m_mouseInput.m_currentState.X, m_mouseInput.m_currentState.Y, m_mouseInput.m_leftButtonPressed))
            {
               
                if (!Guide.IsVisible)
                {
                    Guide.BeginShowKeyboardInput(PlayerIndex.One, "Edit Filename", "Please enter a file name", "save1", new AsyncCallback(GetFileName), null);
                }
            }
            if (m_text.DrawClickText(10, 30, "Starting Penguins: " + m_grid.m_startingPenguins, m_mouseInput.m_currentState.X, m_mouseInput.m_currentState.Y, m_mouseInput.m_leftButtonPressed))
            {
                if (!Guide.IsVisible)
                {
                    Guide.BeginShowKeyboardInput(PlayerIndex.One, "Starting Penguins", "Please enter starting penguins", "0", new AsyncCallback(UpdateStartingPenguins),null);
                }

            }
            if (m_text.DrawClickText(10, 50, "Par: " + m_grid.m_parPenguins, m_mouseInput.m_currentState.X, m_mouseInput.m_currentState.Y, m_mouseInput.m_leftButtonPressed))
            {
                if (!Guide.IsVisible)
                {
                    Guide.BeginShowKeyboardInput(PlayerIndex.One, "Par", "Please enter par", "0", new AsyncCallback(UpdatePar), null);
                }

            }



            m_text.DrawText(1100, 10, "F1 - Start Flag");
            m_text.DrawText(1100, 30, "F2 - End Flag");
            m_text.DrawText(1100, 50, "F3 - Place Bear");
            m_text.DrawText(1100, 70, "F4 - Clear Bears");
            m_text.DrawText(1100, 90, "F5 - Load File");
            m_text.DrawText(1100, 110, "F6 - Save File");

            DrawTilePreview();

            base.Draw(gameTime);
        }


        private void DrawTilePreview()
        {
            m_text.DrawText(1100, 130, m_currentTileType.ToString());
        }

        private void GetFileName(IAsyncResult ar)
        {
            m_path = Guide.EndShowKeyboardInput(ar);

            if (m_path == null)
            {
                m_path = m_defaultpath;
            }
        }

        private void UpdateStartingPenguins(IAsyncResult ar)
        {
            string startingPenguins = Guide.EndShowKeyboardInput(ar);
            if (startingPenguins == null)
            {
                startingPenguins = "0";
            }
    
            m_grid.m_startingPenguins = int.Parse(startingPenguins);
        }

        private void UpdatePar(IAsyncResult ar)
        {
            string par = Guide.EndShowKeyboardInput(ar);
            if (par == null)
            {
                par = "0";
            }

            m_grid.m_parPenguins = int.Parse(par);
        }


        public string Path
        {
            get
            {
                return m_path;
            }
            set
            {
                m_path = value;
            }
        }

        private string m_defaultpath = "save";
        private string m_path = "save";

        private Grid m_grid;
        private Texture2D m_nullTexture;

        private List<Texture2D> m_tileTextureList;

        private Texture2D m_startFlagTexture;
        private Texture2D m_endFlagTexture;
        private Texture2D m_bearStartTexture;
        
        public Vector2 m_scroll;
        public MouseInput m_mouseInput;

        private KeyboardState m_currentKeyState;
        private KeyboardState m_previousKeyState;

        public Tile.TileTypes m_currentTileType;

        private Text m_text;
        private SpriteFont m_font;

 

        enum EditingMode
        {
            None,
            Path
        }

        KeyboardState oldKeyState;
        EditingMode editMode = EditingMode.None;



    }
}
